package ch.zhaw.skuh.turing.model.turingmaschine;

import ch.zhaw.skuh.turing.controller.Factory;

public class Addition extends TuringChar {

	// not advisable for large rule-sets (large alphabets or many tapes) !!!
	protected static boolean RULEOUTPUT_ENABLED = true;
	
	private static int COUNTSTATES = 4;
	private static int[] ACCEPT = { 3 };

	private static int TAPES = 1;
	
	private static String NAME = "Addition";
	
	//shortcuts
	private static String B = "_";
	private static String O = "0";
	private static String I = "1";
	
	// Alphabet: "Blank" must be in first position!
	private static String ABC = B + O + I;
	
	//creation as arrays (we might use more tapes later)
	private static int[] R = {1};
	private static int[] L = {-1};
	
	//the calculated result
	private int calcResult = 0;

	public Addition() {
		super(COUNTSTATES, ABC, B.toCharArray()[0], ACCEPT, TAPES, NAME);
	}
	
	private void initRules(){
		// short-hand notation (watch static values!)
		// Example:
		// (q0, 1) > (q0, 1, R)
		// short for:
		// addRule(0, "1", 0, "1", +1);
		// shorter, with static vars mapped to alphabet positions
		// addRule(0, I, 0, I, R);
		// meaning (q0, 1) -> (q0, 1, >)
		
		// *** q0 rules ***
		// (search forward for 0, replace with 1 & goto q1)
		// (q0, 1) > (q0, 1, R)
		// (q0, 0) > (q1, 1, R)
		// (q0, B) > (q3, B, R)
		super.addRule(0, I, 0, I, R);
		super.addRule(0, O, 1, I, R);
		// addRule(0, B, 3, B, 1);
		// *** q1 rules ***
		// find end & goto q2
		// (q1, 1) > (q1, 1, R)
		// (q1, 0) > (q1, 0, R)
		// (q1, B) > (q2, B, L)
		super.addRule(1, I, 1, I, R);
		super.addRule(1, O, 1, O, R);
		super.addRule(1, B, 2, B, L);
		// *** q2 rules ***
		// replace last 1 with B goto q3
		// (q2, 1) > (q3, B, L)
		super.addRule(2, I, 3, B, L);
		// *** q3 rules ***
		// find backwards first 0, replace with 1 & goto q1
		// (q3, 0) > (q1, 1, R)
		super.addRule(3, O, 1, I, R);
		super.addRule(3, I, 3, I, L);
	}

	@Override
	public boolean validateInput(String text) {
		return Factory.validateNumberList(text, Factory.DELIMITER);
	}

	@Override
	public boolean isOutputEnabled() {
		return true;
	}

	@Override
	public void setTapes(String input) {		
		long[] list = Factory.toNumber(input, Factory.DELIMITER);
		StringBuilder sb = new StringBuilder();
		this.calcResult = 0;
		for(int i=0;i<list.length;i++){
			//calc result
			this.calcResult+=list[i];
			//fill tape
			for(int j=0;j<list[i];j++){
				sb.append(I);
			}
			//delimiter char
			if(i<list.length-1){
				sb.append(O);
			}
		}
		//only 1 tape
		char[][] charInput = new char[1][];
		charInput[0] = sb.toString().toCharArray();
		//call super class method (which handles the rest)
		setTapes(charInput);
		//rules cannot be added until now
		initRules();
	}

	@Override
	public String getResult() {
		if(getMaschine().hasRule()){
			return null;
		}
		else{
			String s = getTape(0);
			int result = Factory.count(s, '1');
			return Integer.toString(result);
		}
	}

	@Override
	public String getResultPrediction() {
		return Integer.toString(this.calcResult);
	}

}
